Repository navigation
engine: a frame the receiver locked onto and lost reaches the chip - #757
Merged
Merged
Conversation
A collision now says where it landed. More than one destroyed symbol inside the eight-symbol header block, coded at CR 4/8, is a header the receiver could not read; anything else lost is a payload that failed its CRC. The firmware's chip is told the same through a new bridge kind, 0x0A, and raises HeaderErr, or RxDone beside CrcErr, as the part does. Waveform mode takes the answer from the demodulator. Before, a lost frame reached the firmware as nothing at all, so every error path in a radio driver went unexercised. A node that does not know the kind skips it, as it skips any kind, and behaves as it always has.
This was referenced Oct 16, 2026
Merged
A native bridge built before kind 0x0A ends its connection on any kind it does not know, so sending it to today's published builds stopped those nodes and failed the run. A node now says it takes the kind with bit 0 of byte 47 of its radio stats record, which every engine reads on length; one that does not say so is sent nothing, as before. The Renode peripheral's handler is withdrawn until Renode can say so too.
…ng to a sized slice
…ilure 3 A frame swamped by interference the receiver could not capture over is told to the chip by when the interference arrived. Arriving while the preamble was still to be found, it left nothing to lock onto, which the part reports by raising nothing; the chip model takes back the HeaderValid it raised from the carrier's length and leaves PreambleDetected latched. Arriving later, it found a receiver that had locked, and is a header or CRC error as before. In waveform mode a frame with no preamble lock is the same third case. Sent only to a node whose radio stats record sets bit 1 of byte 47, because a chip older than virtual-sx1262 ABI 1.7 reads failure 3 as a CRC error.
A13xB0
commented
Oct 24, 2026
A13xB0
left a comment
Collaborator
Author
There was a problem hiding this comment.
The approach is sound. The capability bit keeps old bridges safe, and failure 3 has its own bit.
- Merge order: virtual-sx1262#7, then meshcore-native#30 and #29, then this, then docs#47. The consumers check on vsx#7 stays red until mcn#30 lands.
rec.Demodnow follows the header, so collision outcomes in the ledger and capture change. That's expected, but experiment numbers will move between releases; worth a changelog note.- The red CI from 17 Oct was the runners' disk filling up, not this change. It's re-running now.
Given the ABI bump, I'd land the set after today's release.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
A frame a receiver locked onto and then lost now reaches that node's firmware as the SX1262 reports it, instead of not at all.
0x0A:[failure][frame...], numbered asvsx_deliver_frame_failednumbers it (1 CRC, 2 header). The chip raisesHeaderErralone, orRxDonebesideCrcErrwith the corrupt bytes in the buffer.HeaderValidit raised from the carrier's length and leavesPreambleDetectedlatched, as the part leaves it. Interference arriving after the lock is a header or CRC error, as above.0x0Awith bit 0 of byte 47 of its radio stats record, which every engine reads on length. A native bridge built before this ends its connection on any kind it does not know (default: goto done), so a node that does not say so is sent nothing. Failure 3 needs bit 1 as well (Receive only what the receiver was listening for meshcore-native#30), because a chip older than ABI 1.7 reads 3 as a CRC error.Why
Before this, every failure was withheld, so a radio driver's error paths never ran in the simulator. MeshCore's
CustomSX1262::isReceiving()treats anyHeaderErras "not receiving" and clearsHeaderValidwith it, even when a newer frame'sHeaderValidsits beside a stale error. That can make a node transmit over a frame it is in the middle of receiving, and it could not be tested here, because nothing ever raisedHeaderErr.Compatibility
Today's published native builds, Renode and QEMU boards never set the bit, so they are never sent
0x0Aand behave exactly as before. A native node built with MeshBench/meshcore-native#29 sets it. Renode and QEMU boards come later: they skip unknown kinds safely, but they cannot say they take this one until their stats records grow to byte 47.The first push of this PR sent the kind to every firmware node, and CI caught it: today's native bridge hung up on it and the experiment and fixture checks failed. That is what the capability bit fixes.
Who loses a frame is unchanged: only what the losing receiver's chip is told.
Still kinder than the part
Written up as
docs/shortcomings.md3.2b:HeaderErrarrives when the packet ends, not when its header does;HeaderValidis raised from the carrier's length, not from a decoded header, and is only taken back when the frame ends without a lock;On native builds with strict receive, the detection flags now stay set as the datasheet says. Emulated boards still clear them with the carrier.
Tests
TestACollisionOnTheHeaderIsAHeaderError: a collision across the header block is reported as a header error, and one after it as a CRC failure. Fails onmain.TestTheFirmwareIsToldWhereAFrameFailed: over a real bridge, the firmware is handed0x0Awith 2 for the header case and 1 for the payload case.TestAFailedFrameReachesOnlyANodeThatTakesIt: a node that has not set the bit is sent nothing; once it has, the wire format.TestANeverLockedFrameReachesOnlyAChipThatReadsIt: failure 3 is withheld from a node that sets only bit 0, and sent once it sets bit 1.TestAFrameSwampedBeforeLockIsOneTheChipNeverLockedOnto: a stronger interferer arriving during the preamble is failure 3; arriving after the header it is a CRC failure.go testfor the engine, firmware and layout packages,go vet,gofmt, the file-length check,golangci-lintv2.12.2 on the changed packages and the lint ratchet all pass.